﻿using Newtonsoft.Json;
using OBS;
using OBS.Model;
using System;
using System.IO;
using up6.db.model;
using Newtonsoft.Json.Linq;

namespace up6.db.store.obs
{
    public class OBSTool
    {

        public static string putObject(string key, byte[] data) { 
            OBSConfig cfg = new OBSConfig();
            ObsClient c = new ObsClient(cfg.ak, cfg.sk, cfg.endpoint);
            // 上传文件
            try
            {
                PutObjectRequest request = new PutObjectRequest()
                {
                    BucketName = cfg.bucket,  //待传入目标桶名
                    ObjectKey = key,   //待传入对象名(不是本地文件名，是文件上传到桶里后展现的对象名)
                    FilePath = "d:\\QQ.exe",//待上传的本地文件路径，需要指定到具体的文件名
                };
                PutObjectResponse response = c.PutObject(request);
                Console.WriteLine("put object response: {0}", response.StatusCode);
            }
            catch (ObsException ex)
            {
                Console.WriteLine("ErrorCode: {0}", ex.ErrorCode);
                Console.WriteLine("ErrorMessage: {0}", ex.ErrorMessage);
            }
            return "";
        }

        /// <summary>
        /// https://support.huaweicloud.com/sdk-dotnet-devg-obs/obs_25_0503.html
        /// </summary>
        /// <param name="key"></param>
        /// <param name="blockOffset"></param>
        /// <param name="blockLen"></param>
        /// <returns></returns>
        /// <exception cref="IOException"></exception>
        public static byte[] getObject(string key, long blockOffset, long blockLen)
        {
            OBSConfig cfg = new OBSConfig();
            // 创建OssClient实例。
            var client = new ObsClient(cfg.ak, cfg.sk, cfg.endpoint);
            try
            {
                MemoryStream mem = new MemoryStream();
                ByteRange range = new ByteRange(blockOffset, blockOffset + blockLen - 1);
                var req = new GetObjectRequest() { 
                    BucketName=cfg.bucket,
                    ObjectKey = key,
                    ByteRange=range
                };

                using (var res = client.GetObject(req))
                {
                    byte[] buf = new byte[1024];
                    var len = 0;
                    while ((len = res.OutputStream.Read(buf, 0, 1024)) != 0)
                    {
                        mem.Write(buf, 0, len);
                    }
                    return mem.ToArray();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Get object failed. {0}", ex.Message);
                var o = JObject.FromObject(ex);
                o["msg"] = "oss get object error";
                throw new IOException(o.ToString());
            }
        }
        /// <summary>
        /// 参考：https://support.huaweicloud.com/sdk-dotnet-devg-obs/obs_25_0408.html
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static String CreateMultipartUpload(String key)
        {
            OBSConfig cfg = new OBSConfig();
            ObsClient c = new ObsClient(cfg.ak, cfg.sk, cfg.endpoint);
            try
            {
                // 1. 初始化分段上传任务
                InitiateMultipartUploadRequest initiateRequest = new InitiateMultipartUploadRequest
                {
                    BucketName = cfg.bucket,
                    ObjectKey = key
                };

                InitiateMultipartUploadResponse res = c.InitiateMultipartUpload(initiateRequest);
                return res.UploadId;

            }
            catch (ObsException ex)
            {
                Console.WriteLine("Exception:{0}", ex.ErrorCode);
                Console.WriteLine("Exception Message:{0}", ex.ErrorMessage);
                throw new Exception("obs CreateMultipartUpload error");
            }
        }

        /// <summary>
        /// https://support.huaweicloud.com/sdk-dotnet-devg-obs/obs_25_0408.html
        /// </summary>
        /// <param name="file"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static string uploadPart(FileInf file, Stream data)
        {
            OBSConfig cfg = new OBSConfig();
            try
            {
                ObsClient c = new ObsClient(cfg.ak, cfg.sk, cfg.endpoint);

                UploadPartRequest uploadRequest = new UploadPartRequest
                {
                    BucketName = cfg.bucket,
                    ObjectKey = file.ossKey(),
                    UploadId = file.object_id,
                    PartNumber = file.blockIndex,
                    PartSize = data.Length,
                    Offset = file.blockOffset,
                    InputStream = data
                };
                var res = c.UploadPart(uploadRequest);
                //序列化
                var json = JsonConvert.SerializeObject(res,new JsonSerializerSettings()
                {
                    ContractResolver = new ObsEtagResolver(new[] { "ETag", "PartNumber" }),
                });
                return json.Replace("\\\"","");
            }
            catch (ObsException e)
            {
                throw new Exception("obs upload part error");
            }
        }

        /// <summary>
        /// API：https://support.huaweicloud.com/api-obs/obs_04_0102.html
        /// SDK：https://support.huaweicloud.com/sdk-dotnet-devg-obs/obs_25_0408.html
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static bool CompleteMultipartUpload(FileInf file)
        {
            OBSConfig cfg = new OBSConfig();
            try
            {
                ObsClient c = new ObsClient(cfg.ak, cfg.sk, cfg.endpoint);
                var cmp = new CompleteMultipartUploadRequest()
                {
                    BucketName = cfg.bucket,
                    ObjectKey = file.ossKey(),
                    UploadId = file.object_id
                };
                cmp.AddPartETags(file.obsEtags());
                CompleteMultipartUploadResponse res = c.CompleteMultipartUpload(cmp);
                return (int)res.StatusCode==200;
            }
            catch (ObsException e)
            {
                throw new Exception("obs CompleteMultipartUpload error");
            }
        }
    }
}